<template>
	<view class="c-tabs">
		<scroll-view scroll-x="true" class="tabs-scroll" scroll-with-animation :scroll-left="scrollLeft">
			<view class="tabs-content">
				<view class="tabs-list">
					<view :class="['tabs-item', 'tabs-item__' + index]" v-for="(item, index) in list" :key="index"
						@click="handleClick(item, index)">
						{{ item[keyName] }}
					</view>
				</view>
				<view class="tabs-item__line" :style="{
						width: lineWidth + 'rpx',
						height: lineHeight + 'rpx',
						backgroundColor: lineColor,
						transform: `translateX(${lineOffsetLeft}px)  `,
						transitionDuration: '0.3s',
						textAlign: 'center'
					}"></view>
			</view>
		</scroll-view>
	</view>
</template>

<script setup>
	/**
	 * 选项卡组件
	 * @description c-tabs通用型选项卡组件
	 * @property {Array} list 选项卡数据来源
	 * @property {Number} current 选项卡当前选中项
	 * @property {String} keyName 选项卡显示字段
	 * @property {String} lineColor line 颜色
	 * @property {Number} lineWidth line 宽
	 * @property {Number} lineHeight line 高
	 * @example <c-tabs :list="[{text: '选项1'}]></c-tabs>"
	 */
	import {
		getCurrentInstance,
		nextTick,
		onMounted,
		reactive,
		toRefs,
		watchEffect
	} from 'vue';
	import _props from './props.js';
	import {
		getSystemInfo
	} from '@/common/tools/index.js';

	const props = defineProps(_props);
	const emits = defineEmits(['change']);

	const query = uni.createSelectorQuery().in(getCurrentInstance());

	const state = reactive({
		tabsList: [],
		index: 0,
		scrollLeft: 0,
		scrollViewWidth: 0,
		lineOffsetLeft: 0,
		tabsRect: {
			left: 0
		}
	});

	watchEffect(() => {
		state.index = props.current;
		state.tabsList = props.list;
		nextTick(() => {
			resize();
		});
	});

	// 点击某一个标签
	function handleClick(item, index) {
		state.index = index;
		resize();
		emits('change', {
			...item,
			index
		});
	}

	function setLineLeft() {
		const tabItem = props.list[state.index];
		if (!tabItem) {
			return;
		}
		// 获取滑块该移动的位置
		let lineOffsetLeft = props.list.slice(0, state.index).reduce((total, curr) => total + curr.rect.width, 0);
		// 获取下划线的数值px表示法
		const lineWidth = uni.upx2px(props.lineWidth);
		state.lineOffsetLeft = lineOffsetLeft + (tabItem.rect.width - lineWidth) / 2;
	}

	function resize() {
		// 如果不存在list，则不处理
		if (props.list.length === 0) {
			return;
		}
		Promise.all([getTabsRect(), getAllItemRect()]).then(([tabsRect, itemRect = []]) => {
			state.tabsRect = tabsRect;
			state.scrollViewWidth = 0;
			itemRect.map((item, index) => {
				// 计算scroll-view的宽度，这里
				state.scrollViewWidth += item.width;
				// 另外计算每一个item的中心点X轴坐标
				props.list[index].rect = item;
			});
			// 获取了tabs的尺寸之后，设置滑块的位置
			setLineLeft();
			setScrollLeft();
		}).catch(err => {
			console.log("resize-err", err);
		});
	}

	function setScrollLeft() {
		// 当前活动tab的布局信息，有tab菜单的width和left(为元素左边界到父元素左边界的距离)等信息
		const tabRect = props.list[state.index];
		// 累加得到当前item到左边的距离
		const offsetLeft = props.list.slice(0, state.index).reduce((total, curr) => {
			return total + curr.rect.width;
		}, 0);
		// 此处为屏幕宽度
		const windowWidth = getSystemInfo().windowWidth;
		// 将活动的tabs-item移动到屏幕正中间，实际上是对scroll-view的移动
		let scrollLeft =
			offsetLeft -
			(state.tabsRect.width - tabRect.rect.width) / 2 -
			(windowWidth - state.tabsRect.right) / 2 +
			state.tabsRect.left / 2;

		// 这里做一个限制，限制scrollLeft的最大值为整个scroll-view宽度减去tabs组件的宽度
		scrollLeft = Math.min(scrollLeft, state.scrollViewWidth - state.tabsRect.width);
		state.scrollLeft = Math.max(0, scrollLeft);

	}

	// 获取导航菜单的尺寸
	function getTabsRect() {
		return new Promise((resolve) => {
			queryRect('.tabs-scroll').then((size) => {
				return resolve(size);
			});
		});
	}

	// 获取所有标签的尺寸
	function getAllItemRect() {
		return new Promise((resolve) => {
			const promiseAllArr = props.list.map((item, index) => {
				return queryRect(`.tabs-item__${index}`, true);
			});
			Promise.all(promiseAllArr).then((sizes) => {
				return resolve(sizes);
			});
		});
	}

	//获取节点信息
	function queryRect(selector) {
		return new Promise((resolve) => {
			query
				.select(selector)
				.boundingClientRect((rect) => {
					resolve(rect);
				})
				.exec();
		});
	}

	const {
		tabsList,
		index,
		scrollLeft,
		lineOffsetLeft
	} = toRefs(state);
</script>

<style lang="scss">
	.c-tabs {
		overflow: hidden;
		// background-color: $bg-inverse-color;
		height: 80rpx;

		.tabs-scroll {
			width: 100%;
			height: 100%;

			.tabs-content {
				position: relative;
				height: 100%;
			}

			.tabs-list {
				display: flex;
				align-items: center;
				// justify-content: center;
				width: 100%;
				height: 100%;

				.tabs-item {
					flex-shrink: 0;
					padding: 0 .8em;
				}
			}

			.tabs-item__line {
				position: absolute;
				bottom: 0;
				width: 70rpx;
				height: 6rpx;
				background-color: red;
				border-radius: $radius-half;
			}
		}
	}
</style>